Add support for React router v8 - #11289
Open
smeng9 wants to merge 57 commits into
Open
Conversation
Member
|
Thanks for your PR, but U'm not fan of the extra compatibility layer & the partial reimplementation. I'd prefer if you created an entirely new adapter for react-router v8 (in a new package). We'd probably need to move the current routing adapter to a package, too. |
Contributor
Author
|
Hi @fzaninotto The ra-router-react-router-v8 is pulled out to a separate package |
fzaninotto
requested changes
Jun 24, 2026
fzaninotto
left a comment
Member
There was a problem hiding this comment.
Thanks. Several remarks:
- This is a new feature, so it must be PRed against
nextand notmaster - As RR v7 is still loaded by default by ra-core, users of RRv8 will end up with 2 versions of RR, leading to probable context conflicts. You also need to extract the default RRv7 adapter to a package in the monorepo
- The new RRv8 adapter needs unit tests in addition to user stories
- you also need to test the basename feature (check the tests of the tanstack router adapter)
Contributor
Author
|
Hi @fzaninotto Can you restore the I have already noted this in the additional checks. |
Member
|
Sure, the |
smeng9
marked this pull request as draft
June 25, 2026 02:21
Contributor
Author
|
Hi @fzaninotto Back to RFR. |
smeng9
marked this pull request as ready for review
June 26, 2026 04:43
React Router v8 merged react-router-dom into react-router and requires React 19. Rather than adding a compatibility layer and partial reimplementation inside ra-core (per review feedback on marmelab#11289), v8 support ships as a standalone, opt-in adapter package mirroring ra-router-tanstack. The adapter is a thin pass-through over react-router v8's native API: the obsolete v6/v7 `future` flags are dropped (now defaults in v8) and imports come from `react-router` instead of `react-router-dom`. ra-core keeps its built-in react-router v6/v7 adapter as the default, so existing apps are unaffected. The package is ESM-only because react-router v8 is ESM-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
After merging the ra-router-react-router-v8 package, the in-core react-router adapter no longer needs the compatibility shims: - reactRouterProvider imports everything from `react-router`, with only `Link` and `createHashRouter` from `react-router-dom` - Form.stories uses `HashRouter` from `react-router-dom` directly - Remove CompatHashRouter, CompatLink and their tests - Restore `react-router-dom` to the dependencies of ra-core, ra-ui-materialui and react-admin, and narrow the react-router range back to ^6.28.1 || ^7.1.1 (v8 is supported via the separate package) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
No code in ra-ui-materialui imports react-router-dom; all routing imports come from react-router. ra-core declares its own react-router-dom peer for its router adapter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Individual zshy builds had rewritten the exports field to the flat pre-normalization form. Restore the nested import/require form that update-package-exports produces and that matches upstream. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-exports update-package-exports forces dual import/require exports on every package; the ESM-only v8 adapter must keep its ESM-only exports (it has no .cjs build). Also keep minor README/story/doc wording. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The resolvePath helper inside useNavigate carries a two-line lead comment plus an inner "Don't prepend if path already includes basename" comment in the tanstack adapter, unlike the one-line form inside Link. Align both router adapters so each call site matches its tanstack counterpart exactly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pter Drop the extra basenameRef; useNavigate now reads basename from the hook and lists it in the useCallback dependency array, matching the tanstack adapter's shape. The navigateRef (react-router-specific, issue marmelab#7634) stays. Behavior unchanged; 107/107 in both adapters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ters Follow the tanstack adapter's useNavigate skeleton exactly: numeric (go back/forward) branch first, then the resolvePath helper, then the object branch, then the string path — with the same comments. Only the call differs (navigateRef.current(to) instead of router.history.go(to)) since react-router's navigate handles all three input shapes. Keeps the three router adapters diff-aligned. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the tanstack adapter's Link: branch on the object form first (`if (typeof to === 'object' && to !== null)`) and fall back to `resolvePath(to as string)` in the else, instead of a nested ternary. Behavior unchanged; 107/107 in both adapters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Build a resolvedPath string via the tanstack Navigate shape (string vs
object branch, append search/hash, then the inline basename-prepend
block) and render <Navigate to={resolvedPath} replace state />. Drops the
to.state merge since react-router's Navigate `to` (a Path) has no state
field — state stays a prop. 107/107 in both adapters.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pass through the rest of the Navigate props ({...rest}) instead of
listing replace/state explicitly, and drop the "(like react-router does)"
aside from the basename comment. 107/107 in both adapters.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rename the provider-local useProviderBasename to useBasename and publish the basename via BasenameContext in both RouterWrapper branches. Fix quote style to satisfy prettier. 107/107 in the react-router adapter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use fireEvent.click for navigation in both router adapter specs, matching the tanstack provider spec's convention, and keep userEvent.setup/user.type only in the two unsaved-changes form tests that need typing. 107/107 in both adapters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restore the tanstack import ordering (PathlessLayoutRoutes before NestedResourcesPrecedence) in both router adapter specs. No behavior change; 107/107 in both adapters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… parity)
The earlier blanket fireEvent.click conversion wrongly flipped the one
test that tanstack drives with user.click ("navigate back to parent app").
Match tanstack per-test: user.click + userEvent.setup there, fireEvent.click
everywhere else. 107/107 in both adapters.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the "// Wait for data to load before clicking" comment that tanstack has between the two findByText calls in the navigate-within-nested-routes test, in both router adapter specs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove the extra explanatory comment atop the matchPath block and reword the useCanBlock test to "should return true for React Router", matching the tanstack spec wording. 107/107 in both adapters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rename to "should decode only path separator in URL-encoded splat values" in both router adapter specs. 107/107. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rename the test to "should decode only path separator in URL-encoded params", restore tanstack's "// UTF-8 characters: 衣類/衣類 encoded" comment, and drop the react-router-specific note. 107/107 in both adapters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rename the three tests to match the tanstack useBlocker wording: "should block navigation when form is dirty", "should allow navigation when clicking proceed", and "should not block navigation when form is not dirty". 107/107 in both adapters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "should block navigation when form is dirty" test was conflating the block (confirm fires) with the cancel outcome (declining keeps you on the form). Split into separate "should block navigation when form is dirty" and "should cancel navigation when clicking cancel" tests, ordered like tanstack (block, proceed, cancel, not-dirty). 108/108 in both adapters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Match the tanstack useBlocker tests, which have no inline comments in the test bodies. 108/108 in both adapters. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…er-dom Part of the React Router v8 migration: v8 merged react-router-dom into react-router. Move Route/Routes/RouterProvider/BrowserRouter doc imports to react-router, while keeping createBrowserRouter and Link on react-router-dom for v6 compatibility. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
BrowserRouter is not exported from the react-router core package in v6 (it is DOM-only, like Link and createBrowserRouter). Revert the two BrowserRouter imports back to react-router-dom; Routes/Route stay on react-router. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`NODE_OPTIONS=--experimental-vm-modules` is process-global, so setting it on the shared `test-unit`/`test-unit-ci` scripts pushed the entire default (CommonJS) jest project into ESM mode. Jest then honored the `"type": "module"` field of transformed dependencies and refused to `require()` them, so every suite that transitively imports an ESM-only dep (e.g. react-hotkeys-hook, pulled in via the layout/button/form barrels) failed to load with "Must use import to load ES Module". This took out 93 suites across ra-ui-materialui, react-admin, ra-input-rich-text and ra-i18n-polyglot — the suites failed to run while their individual tests never executed. Keep the root config a single CommonJS project (no `projects` array, no flag) and run ra-router-react-router-next's ESM/React 19 tests as a separate jest invocation against its own jest.config.cjs, appended to the test scripts with the flag set only for that run. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-next The package imports react-router at runtime, so it belongs in `dependencies` (matching the sibling ra-router-react-router), not only in dev/peer deps. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ra-core is provided by the react-admin meta-package at runtime; the sibling ra-router-react-router does not declare it either. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restore ra-core as a peerDependency of ra-router-react-router-next (it is provided by the host app, like the other ra-router adapters), and declare react-router as a peerDependency of ra-no-code. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
react-admin imports from react-router (via ra-router-react-router), not react-router-dom directly, so the devDependency is unnecessary. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The auth spec asserted on the post-logout/post-login URL with cy.url().then(url => expect(url).to.contain(...)), which evaluates the assertion exactly once before the redirect has necessarily landed, causing intermittent CI failures. Switch to the retrying cy.url().should() form already used elsewhere in the file. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Rebased after |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
react-router v8 is out
Solution
Follow #10440
Add support for React router v8
Find a way to avoid dependency resolution issue after dropping
react-router-domHow To Test
Build RA packages locally, then link with apps in /examples folder
Additional Checks
masterfor a bugfix or a documentation fix, ornextfor a featurenextbranch seems is disappeared, I assumemasterbranch can be used for new features.Needs to be end-2-end tested with /examples folder.
Stories using the routers are updated.
Also, please make sure to read the contributing guidelines.